#include "student.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

static char* subject[] = {"数学","语文","英语"};
static status StuExtendCapcity(StuManage* stu);
static status StuChangeMessageByIndex(StuManage* stu,int i);
static status StuChangeScoreByIndex(StuManage* stu,int i);
static status StuDelByIndex(StuManage *stu,int i);
static status StuIdIsExist(StuManage* stu,int id,int* index,int ifindOrFind);
static status StuAccountIsOne(StuManage* stu,char* account);
static status StuIdIsOne(StuManage* stu,int id);

status StuInit(StuManage* stu){

    assert(stu);

    Student* p = (Student*)malloc(sizeof(Student) * STUDENT_INIT_CAPCITY);
    if(!p) exit(OVERFLOW);

    stu->student = p;
    stu->capcity = STUDENT_INIT_CAPCITY;
    stu->numOfStu = 0;

    return OK;
}

//插入学生信息(不包括成绩)
status StuInsert(StuManage* stu,int i){

    assert(stu && (i>=1 && i<=stu->numOfStu+1));

    //判断是否扩容
    if(stu->numOfStu == stu->capcity)
        if(StuExtendCapcity(stu) == ERROR)
            return ERROR;

    Student *p1 = stu->student+stu->numOfStu-1; //最后一个学生地址
    Student *p2 = stu->student+i-1; //第i个同学地址

    for(;p1 >= p2;p1--){
        *(p1+1) = *p1;
    }

    //开始赋值 不包含成绩
    StuInputMessage(stu,i,STU_INSERT);

    memset(&((stu->student+i-1)->score),0,(sizeof(subject)/sizeof(subject[0])+1)*sizeof(double));

    ++stu->numOfStu;

    return OK;
}

//输入信息(不包括成绩) 分两种 新插入学生输入信息 修改学生信息输入信息
status StuInputMessage(StuManage* stu,int i,int insertOrChange){

    if(insertOrChange == STU_INSERT) 
        assert(stu && (i>=1 && i<=stu->numOfStu+1));
    else if(insertOrChange == STU_CHANGE)
        assert(stu && (i>=1 && i<=stu->numOfStu));
    else return ERROR;

    int index = -1;
    char temp[TEMP_SIZE];

    while(1){

        printf("请输入账户(%d位 "STUACCOUNT_FLAG"开头)>",ACCOUNT_SIZE-1);
        memset(temp,0,TEMP_SIZE);
        scanf("%s",temp);

        //判断账户是否符合格式
        if( (strlen(temp)==ACCOUNT_SIZE-1) && \
            (strncmp(temp,STUACCOUNT_FLAG,strlen(STUACCOUNT_FLAG))==0) ){

                if( (insertOrChange == STU_INSERT) && \
                    (StuAccountIsExist(stu,temp,&index,STU_IFIND) == NOTEXIST) ){

                    memcpy((stu->student+i-1)->account,temp,ACCOUNT_SIZE);
                    printf("账户输入成功\n");
                    break;
                }
                else if(insertOrChange == STU_CHANGE){

                    memcpy((stu->student+i-1)->account,temp,ACCOUNT_SIZE);
                
                    if(StuAccountIsOne(stu,temp) == OK){

                        printf("账户输入成功\n");
                        break;
                    }
                }
            }

        printf("输入有误\n");
    }

    while(1){

        printf("请输入密码(%d位以内)>",PASSWD_SIZE-1);
        memset(temp,0,TEMP_SIZE);
        
        scanf("%s",temp);
        if(strlen(temp) < PASSWD_SIZE){
            
            memcpy((stu->student+i-1)->passwd,temp,strlen(temp)+1);
            printf("密码输入成功\n");
            break;
        }

        printf("输入有误\n");
    }

    while(1){

        int idTemp = 0;
        printf("请输入id(%d位及以内)>",ID_SIZE);
        scanf("%d",&idTemp);

        if(insertOrChange == STU_INSERT){

            if(StuIdIsExist(stu,idTemp,&index,STU_IFIND) == NOTEXIST){

                (stu->student+i-1)->id = idTemp;
                printf("id输入成功\n");
                break;
            }
        }
        else if( insertOrChange == STU_CHANGE){

            (stu->student+i-1)->id = idTemp;

            if(StuIdIsOne(stu,idTemp) == OK){

                printf("id输入成功\n");
                break;
            }

        }
        
        printf("输入有误\n");
    }


    printf("请输入姓名>");
    memset(temp,0,TEMP_SIZE);
    scanf("%s",temp);
    strncpy((stu->student+i-1)->name,temp,NAME_SIZE);
    (stu->student+i)->name[NAME_SIZE-1] = '\0';

    while(1){

        int ageTemp;
        printf("请输入年龄>");
        scanf("%d",&ageTemp);

        if(ageTemp>0 && ageTemp<=150){

            (stu->student+i-1)->age = ageTemp;
            printf("年龄输入成功\n");
            break;
        }
    }

    return OK;
}

//输入成绩
status StuInputScore(StuManage* stu,int i){

    assert(stu && (i>=1 && i<=stu->numOfStu));

    printf("请输入%s的分数\n",(stu->student+i-1)->name);
    (stu->student+i-1)->score.sum = 0;

    for(int j = 0;j < sizeof(subject)/sizeof(subject[0]);j++){        

        while(1){

            double score = 0;
            printf("请输入%s的成绩>",subject[j]);
            scanf("%lf",&score);

            if(score>=0.0 && score<=100.0){

                (stu->student+i-1)->score.sum += score;
                *(&((stu->student+i-1)->score.mathScore)+j) = score;
                break;
            }

            printf("成绩输入错误\n");
        }
    }

    return OK;
}

//修改信息 (根据位置)
static status StuChangeMessageByIndex(StuManage* stu,int i){

    assert(stu && (i>0 && i<=stu->numOfStu));

    return StuInputMessage(stu,i,STU_CHANGE);
}

//修改信息 (根据id)
status StuChangeMessageById(StuManage* stu,int id){

    assert(stu);

    int index = -1;
    if(StuIdIsExist(stu,id,&index,STU_FIND) == NOTEXIST)
        return ERROR;
    
    return StuChangeMessageByIndex(stu,index+1);
}

//修改分数 (根据位置)
static status StuChangeScoreByIndex(StuManage* stu,int i){

    assert(stu && (i>=1 && i <=stu->numOfStu));

    return StuInputScore(stu,i);
}

//修改分数 (根据id)
status StuChangeScoreById(StuManage* stu,int id){

    assert(stu && (id>=1 && id <= stu->numOfStu));

    int index = -1;
    if(StuIdIsExist(stu,id,&index,STU_FIND) == NOTEXIST)
        return ERROR;
    
    return StuInputScore(stu,index+1);
}

static status StuDelByIndex(StuManage *stu,int i){

    assert(stu && (i>=1 && i<= stu->numOfStu));

    Student *p1 = stu->student+i-1;
    Student *p2 = stu->student+stu->numOfStu-1;

    for(++p1;p1<=p2;p1++){
        *(p1-1) = *p1;
    }

    --stu->numOfStu;

    return OK;
}

status StuDelById(StuManage* stu,int id){

    assert(stu);

    int index = -1;

    if(StuIdIsExist(stu,id,&index,STU_FIND) == NOTEXIST)
        return ERROR;

    return StuDelByIndex(stu,index+1);
}

int compById(const void* p1,const void* p2){

    return (((Student*)p1)->id - ((Student*)p2)->id);
}

status StuSortById(StuManage* stu){

    assert(stu);

    qsort(stu->student,stu->numOfStu,sizeof(Student),compById);

    return OK;
}

int compByScore(const void* p1,const void* p2){

    return (((Student*)p1)->score.sum - ((Student*)p2)->score.sum);
}

status StuSortByScore(StuManage* stu){

    assert(stu);

    qsort(stu->student,stu->numOfStu,sizeof(Student),compByScore);

    return OK;
}

void StuShowScore(StuManage* stu,int start,int end){

    assert(stu && start>0 && end<=stu->numOfStu);

    printf("id\t姓名\t数学\t语文\t英语\t总分\n");

    for(int i = start;i <= end;i++){

        Student* p = stu->student+i-1;

        printf("%d\t%s\t%.1lf\t%.1lf\t%.1lf\t%.1lf\n", \
        p->id,p->name,p->score.mathScore,p->score.chineseScore,p->score.EnglishScore,p->score.sum);
    }
}

status StuShowAllById(StuManage* stu,int id){

    assert(stu);

    int index = -1;

    if(StuIdIsExist(stu,id,&index,STU_FIND) == NOTEXIST)
        return ERROR;
        
    printf("账号\t\t密码\tid\t姓名\t年龄\t数学\t语文\t英语\t总分\n");

    Student* p = stu->student+index;

    printf("%s\t%s\t%d\t%s\t%d\t%.1lf\t%.1lf\t%.1lf\t%.1lf\n", \
    p->account,p->passwd,p->id,p->name,p->age, \
    p->score.mathScore,p->score.chineseScore,p->score.EnglishScore,p->score.sum);

    return OK;
}

void StuShowAll(StuManage* stu){

    assert(stu);

    printf("账号\t\t密码\tid\t姓名\t年龄\t数学\t语文\t英语\t总分\n");

    for(int i = 0;i < stu->numOfStu;i++){

        Student* p = stu->student+i;

        printf("%s\t%s\t%d\t%s\t%d\t%.1lf\t%.1lf\t%.1lf\t%.1lf\n", \
        p->account,p->passwd,p->id,p->name,p->age, \
        p->score.mathScore,p->score.chineseScore,p->score.EnglishScore,p->score.sum);
    }
    
}

//进行扩容
static status StuExtendCapcity(StuManage* stu){

    assert(stu);

    int newCapcity = stu->capcity + STUDENT_INCREASE;
    Student* p = (Student*)realloc(stu->student,sizeof(Student)*(newCapcity));
    if(!p) exit(OVERFLOW);
    
    stu->student = p;
    stu->capcity = newCapcity;

    return OK;
}

//可进行普通查找和插入数据后移后查找 输入的账户是否存在 index记录下标
status StuAccountIsExist(StuManage* stu,char* account,int* index,int ifindOrFind){

    assert(stu && account && index);

    int j = ( (ifindOrFind==STU_FIND) ? (stu->numOfStu) : \
            ((stu->numOfStu>1) ? (stu->numOfStu+1) : (stu->numOfStu)) );

    for(int i = 0;i < j;i++){

        if(strcmp((stu->student+i)->account,account) == 0){

            *index = i;
            return EXIST;
        }
    }

    return NOTEXIST;
}

static status StuIdIsExist(StuManage* stu,int id,int* index,int ifindOrFind){

    assert(stu && index);

    int j = ( (ifindOrFind==STU_FIND) ? (stu->numOfStu) : \
              ((stu->numOfStu>1) ? (stu->numOfStu+1) : (stu->numOfStu)) );

    for(int i = 0;i < j;i++){

        if((stu->student+i)->id == id){
            
            *index = i;
            return EXIST;
        }
    }

    return NOTEXIST;
}

//检验修改后的账户是否合格 (账户只有一个)
static status StuAccountIsOne(StuManage* stu,char* account){

    assert(stu && account);

    int cnt = 0;

    for(int i = 0;i < stu->numOfStu;i++){

        if(strcmp((stu->student+i)->account,account) == 0)
            if(++cnt > 1) return ERROR;
    }

    return OK;
}

//检验修改后的id是否合格 (id只有一个)
static status StuIdIsOne(StuManage* stu,int id){

    assert(stu);

    int cnt = 0;

    for(int i = 0;i < stu->numOfStu;i++){

        if((stu->student+i)->id == id)
            if(++cnt > 1) return ERROR;
    }

    return OK;
}
